package com.example.voicechat;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import okhttp3.*;
import android.util.Log;
import android.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 语音听写流式 WebAPI 接口调用示例 接口文档（必看）：https://doc.xfyun.cn/rest_api/语音听写（流式版）.html
 * webapi 听写服务参考帖子（必看）：http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=38947&extra=
 * 语音听写流式WebAPI 服务，热词使用方式：登陆开放平台https://www.xfyun.cn/后，找到控制台--我的应用---语音听写---个性化热词，上传热词
 * 注意：热词只能在识别的时候会增加热词的识别权重，需要注意的是增加相应词条的识别率，但并不是绝对的，具体效果以您测试为准。
 * 错误码链接：https://www.xfyun.cn/document/error-code （code返回错误码时必看）
 * 语音听写流式WebAPI 服务，方言或小语种试用方法：登陆开放平台https://www.xfyun.cn/后，在控制台--语音听写（流式）--方言/语种处添加
 * 添加后会显示该方言/语种的参数值
 * @author iflytek
 */

public class WebIATWS extends WebSocketListener {
    private static final String TAG = "ljf_WebIATWS";  // 添加统一的TAG前缀
    private static final String hostUrl = "https://iat-api.xfyun.cn/v2/iat"; //中英文，http url 不支持解析 ws/wss schema
    // private static final String hostUrl = "https://iat-niche-api.xfyun.cn/v2/iat";//小语种
	private static final String appid = "38c280fa"; //在控制台-我的应用获取
	private static final String apiSecret = "ODQxYzkwNjRmNjEzYjhjMzg0ZGE2ZTNj"; //在控制台-我的应用-语音听写（流式版）获取
	private static final String apiKey = "bb08bdeb17fbe15758240eeb6f72e155"; //在控制台-我的应用-语音听写（流式版）获取
    private static final String file = "resource\\iat\\16k_10.pcm"; // 中文
    public static final int StatusFirstFrame = 0;
    public static final int StatusContinueFrame = 1;
    public static final int StatusLastFrame = 2;
    public static final Gson json = new Gson();
    Decoder decoder = new Decoder();
    // 开始时间
    private static Date dateBegin = new Date();
    // 结束时间
    private static Date dateEnd = new Date();
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss.SSS");

    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        super.onOpen(webSocket, response);
        Log.e(TAG, "WebSocket连接已建立");
    }
    @Override
    public void onMessage(WebSocket webSocket, String text) {
        super.onMessage(webSocket, text);
        Log.e(TAG, "收到服务器消息：" + text);
        
        ResponseData resp = json.fromJson(text, ResponseData.class);
        if (resp != null) {
            if (resp.getCode() != 0) {
                Log.e(TAG, "识别错误: code=" + resp.getCode() + " error=" + resp.getMessage() + " sid=" + resp.getSid());
                return;
            }
            
            if (resp.getData() != null && resp.getData().getResult() != null) {
                decoder.decode(resp.getData().getResult().getText());
                if (resp.getData().getStatus() == 2) {
                    Log.e(TAG, "最终识别结果：" + decoder.toString());
                }
            } else {
                Log.e(TAG, "响应数据为空");
            }
        } else {
            Log.e(TAG, "解析响应失败");
        }
    }
    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        super.onFailure(webSocket, t, response);
        Log.e(TAG, "WebSocket连接失败: " + t.getMessage());
        try {
            if (null != response) {
                int code = response.code();
                Log.e(TAG, "失败代码: " + code);
                Log.e(TAG, "失败响应: " + response.body().string());
                if (101 != code) {
                    Log.e(TAG, "连接失败");
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "处理失败响应时出错", e);
        }
    }
    @Override
    public void onClosing(WebSocket webSocket, int code, String reason) {
        super.onClosing(webSocket, code, reason);
        Log.e(TAG, "WebSocket正在关闭: code=" + code + ", reason=" + reason);
    }
    @Override
    public void onClosed(WebSocket webSocket, int code, String reason) {
        super.onClosed(webSocket, code, reason);
        Log.e(TAG, "WebSocket已关闭: code=" + code + ", reason=" + reason);
    }
    public static void main(String[] args) throws Exception {
        // 构建鉴权url
        String authUrl = getAuthUrl(hostUrl, apiKey, apiSecret);
        OkHttpClient client = new OkHttpClient.Builder().build();
        //将url中的 schema http://和https://分别替换为ws:// 和 wss://
        String url = authUrl.toString().replace("http://", "ws://").replace("https://", "wss://");
        //System.out.println(url);
        Request request = new Request.Builder().url(url).build();
        // System.out.println(client.newCall(request).execute());
        //System.out.println("url===>" + url);
        WebSocket webSocket = client.newWebSocket(request, new WebIATWS());
    }
    public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
        URL url = new URL(hostUrl);
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").//
                append("date: ").append(date).append("\n").//
                append("GET ").append(url.getPath()).append(" HTTP/1.1");
        //System.out.println(builder);
        Charset charset = Charset.forName("UTF-8");
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
        String sha = Base64.encodeToString(hexDigits, Base64.NO_WRAP);

        //System.out.println(sha);
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
        //System.out.println(authorization);
        HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().//
                addQueryParameter("authorization", Base64.encodeToString(authorization.getBytes(charset), Base64.NO_WRAP)).//
                addQueryParameter("date", date).//
                addQueryParameter("host", url.getHost()).//
                build();
        return httpUrl.toString();
    }
    public static class ResponseData {
        private int code;
        private String message;
        private String sid;
        private Data data;
        public int getCode() {
            return code;
        }
        public String getMessage() {
            return this.message;
        }
        public String getSid() {
            return sid;
        }
        public Data getData() {
            return data;
        }
    }
    public static class Data {
        private int status;
        private Result result;
        public int getStatus() {
            return status;
        }
        public Result getResult() {
            return result;
        }
    }
    public static class Result {
        int bg;
        int ed;
        String pgs;
        int[] rg;
        int sn;
        Ws[] ws;
        boolean ls;
        JsonObject vad;

        public Text getText() {
            Text text = new Text();
            StringBuilder sb = new StringBuilder();
            
            if (this.ws == null || this.ws.length == 0) {
                Log.e(TAG, "识别结果为空: ws is null or empty");
                return text;
            }

            try {
                for (Ws ws : this.ws) {
                    if (ws.cw != null && ws.cw.length > 0) {
                        sb.append(ws.cw[0].w);
                    }
                }
                
                Log.e(TAG, "识别文本内容: " + sb.toString());
                
                text.sn = this.sn;
                text.text = sb.toString();
                text.rg = this.rg;
                text.pgs = this.pgs;
                text.bg = this.bg;
                text.ed = this.ed;
                text.ls = this.ls;
                text.vad = this.vad;
                
                return text;
            } catch (Exception e) {
                Log.e(TAG, "处理识别结果时出错: " + e.getMessage());
                return text;
            }
        }
    }
    public static class Ws {
        Cw[] cw;
        int bg;
        int ed;
        
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            if (this.cw != null) {
                for (Cw cw : this.cw) {
                    if (cw != null && cw.w != null) {
                        sb.append(cw.w);
                    }
                }
            }
            Log.e(TAG, "Ws内容: " + sb.toString());
            return sb.toString();
        }
    }
    public static class Cw {
        int sc;
        String w;
    }
    public static class Text {
        int sn;
        int bg;
        int ed;
        String text;
        String pgs;
        int[] rg;
        boolean deleted;
        boolean ls;
        JsonObject vad;
        @Override
        public String toString() {
            return "Text{" +
                    "bg=" + bg +
                    ", ed=" + ed +
                    ", ls=" + ls +
                    ", sn=" + sn +
                    ", text='" + text + '\'' +
                    ", pgs=" + pgs +
                    ", rg=" + Arrays.toString(rg) +
                    ", deleted=" + deleted +
                    ", vad=" + (vad==null ? "null" : vad.getAsJsonArray("ws").toString()) +
                    '}';
        }
    }
    //解析返回数据，仅供参考
    public static class Decoder {
        private Text[] texts;
        private int defc = 10;
        
        public Decoder() {
            this.texts = new Text[this.defc];
        }
        
        public synchronized void decode(Text text) {
            if (text == null) {
                Log.e(TAG, "解码器收到空的文本");
                return;
            }
            
            Log.e(TAG, "解码器收到文本: " + text.toString());
            
            if (text.sn >= this.defc) {
                this.resize();
            }
            if ("rpl".equals(text.pgs)) {
                for (int i = text.rg[0]; i <= text.rg[1]; i++) {
                    this.texts[i].deleted = true;
                }
            }
            this.texts[text.sn] = text;
        }
        
        public String toString() {
            StringBuilder sb = new StringBuilder();
            for (Text t : this.texts) {
                if (t != null && !t.deleted) {
                    sb.append(t.text);
                }
            }
            String result = sb.toString();
            Log.e(TAG, "解码器最终结果: " + result);
            return result;
        }
        
        public void resize() {
            int oc = this.defc;
            this.defc <<= 1;
            Text[] old = this.texts;
            this.texts = new Text[this.defc];
            for (int i = 0; i < oc; i++) {
                this.texts[i] = old[i];
            }
        }
        
        public void discard(){
            for(int i=0;i<this.texts.length;i++){
                this.texts[i]= null;
            }
        }
    }
}